using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms.Design;

namespace System.Windows.Forms
{
    internal class ShapeStyleEditor : System.Drawing.Design.UITypeEditor
    {
        public ShapeStyleEditor()
        {
        }

        // Displays the UI for value selection.
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
        {
            // Return the value if the value is not of type Shape
            if (value.GetType() != typeof(ShapeStyle))
                return value;

            // Uses the IWindowsFormsEditorService to display a
            // drop-down UI in the Properties window.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {
                // Display an Shape Type Editor Control and retrieve the value.
                ShapeEditorControl editor = new ShapeEditorControl((ShapeStyle)value);
                edSvc.DropDownControl(editor);

                // Return the value in the appropraite data format.
                if (value.GetType() == typeof(ShapeStyle))
                    return editor.style;
            }
            return value;
        }

        // Indicates whether the UITypeEditor provides a form-based (modal) dialog,
        // drop down dialog, or no UI outside of the properties window.
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.DropDown;
        }

        // Indicates whether the UITypeEditor supports painting a
        // representation of a property's value.
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;
        }

        // Draws a representation of the property's value.
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        public override void PaintValue(System.Drawing.Design.PaintValueEventArgs e)
        {
            ShapeStyle style = (ShapeStyle)e.Value;
            Bitmap bm = new Bitmap(e.Bounds.Width + 4, e.Bounds.Height + 4, e.Graphics);
            Graphics g = Graphics.FromImage(bm);
            ShapeEditorControl.DrawShape(style, g, new Size(e.Bounds.Width - 4, e.Bounds.Height - 4));
            e.Graphics.DrawImage(bm, 3, 3, new Rectangle(new Point(0, 0), new Size(e.Bounds.Width, e.Bounds.Height)), GraphicsUnit.Pixel);
        }
    }

    internal class ShapeEditorControl : System.Windows.Forms.UserControl
    {
        // Stores the shape
        public ShapeStyle style;

        // Specification for the UI
        //number of shapes
        //number of rows
        //number of columns
        private int _numshape, _numrow, _numcol, _width = 20,  //width of each shape
                 _height = 20; //height of each shape

        public ShapeEditorControl(ShapeStyle initial_style)
        {
            this.style = initial_style;
            //Find the number of shapes in the enumeration
            int numshape = Enum.GetValues(typeof(ShapeStyle)).GetLength(0);

            //Find the number of rows and colums to accomodate the shapes
            int numcol = 0, numrow = 0;
            numrow = (int)(Math.Sqrt(numshape));
            numcol = numshape / numrow;
            if (numshape % numcol > 0) numcol++;

            //Record the specifications
            _numshape = numshape;
            _numrow = numrow;
            _numcol = numcol;
            this.Width = _numcol * _width + (_numcol - 1) * 6 + 2 * 4;
            this.Height = _numrow * _height + (_numrow - 1) * 6 + 2 * 4;
        }

        internal static void DrawShape(ShapeStyle style, Graphics g, Size size)
        {
            if (style != ShapeStyle.UserDefined)
            {
                Shape shape = new Shape();
                shape.ShapeStyle = style;
                shape.Size = size;
                shape.Fill.Color1 = Color.Yellow;
                shape.Line.Color = Color.DarkGray;
                shape.Line.Width = 1;
                shape.PaintShape(g);
            }
            else
                g.DrawString("?", new Font("Arial", size.Height / 2), Brushes.Black, 0, 0);
        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button.Equals(MouseButtons.Left))
            {
                int x, y;
                int n;
                x = e.X; y = e.Y;
                n = (y / (this.Height / _numrow)) * _numcol + ((x / (this.Width / _numcol)) % _numcol);

                int count = 0;

                foreach (ShapeStyle style in Enum.GetValues(typeof(ShapeStyle)))
                {
                    if (count == n)
                    {
                        this.style = style;
                        //close the editor immediately
                        SendKeys.Send("{ENTER}");
                    }
                    count++;
                }
            }
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            Bitmap bm = new Bitmap(this.Width, this.Height, e.Graphics);
            Graphics g = Graphics.FromImage(bm);
            e.Graphics.FillRectangle(SystemBrushes.ControlLight, e.ClipRectangle);
            int x = 4, y = 4;
            int n = 0;
            foreach (ShapeStyle style in Enum.GetValues(typeof(ShapeStyle)))
            {
                g.Clear(SystemColors.ControlLight);
                DrawShape(style, g, new Size(_width, _height));
                e.Graphics.DrawImage(bm, x, y, new Rectangle(new Point(0, 0), new Size(_width + 1, _height + 1)), GraphicsUnit.Pixel);
                if (this.style.Equals(style))
                {
                    e.Graphics.DrawRectangle(Pens.Black, new Rectangle(new Point(x - 2, y - 2), new Size(_width + 3, _height + 3)));
                }
                n++;
                x = (n % _numcol) * (_width); x = x + (n % _numcol) * 6 + 4;
                y = (n / _numcol) * (_height); y = y + (n / _numcol) * 6 + 4;
            }
        }

        private void InitializeComponent()
        {
            this.BackColor = System.Drawing.Color.LightGray;
            this.Name = "ShapeEditorControl";
        }
    }
}